/***********************************************************
 * btree.c - Implement bTree.
 *
 ***********************************************************/

#include  "bTree.h"

#include  <stdlib.h>
#include  <stdio.h>
#include  <assert.h>
#include  <memory.h>
#include  <stdarg.h>

#define ISNULL -1

static void node_init( struct btree_node * node, off_t data );
int bintree_find (const struct btree * tree, const struct btree_node * node, off_t node_idx, void * find_data);
void bintree_query (const struct btree * tree, const struct btree_node * node, void * find_data,
		    void*(*handler)(const void*,void*), void * handler_state);


struct btree * btree_new_memory(size_t objectSize)
{
  struct btree * tree = (struct btree *) malloc(sizeof(struct btree));

  tree->oStore = store_open_memory(objectSize, 100);
  tree->nStore = store_open_memory(sizeof(struct btree_node), 100);
  
  tree->root = ISNULL;
 
  return tree;
}

struct btree * btree_new_cached(struct store * store, const char * nFile, const char * nFat,
				size_t cacheSize, int (*compare)(const void*, const void*)) {
  struct btree * tree = (struct btree *) malloc(sizeof(struct btree));
  struct btree_node * oldRoot;
  tree->compare = compare;
  tree->oStore = store;
  tree->nStore = store_open_cached(nFile, nFat, sizeof(struct btree_node), 100, cacheSize);
  
  oldRoot = store_read(tree->nStore, 0);
  if(oldRoot->father !=ISNULL) { // ISNULL => tree already existed on disk.
    
    //New file
    assert(oldRoot->father == 0 &&
	   oldRoot->left   == 0 &&
	   oldRoot->right  == 0);

    assert(store_new(tree->nStore) == 0);
   
    oldRoot->father = ISNULL;
    oldRoot->data   = ISNULL;

    store_write(tree->nStore, 0);
    tree->root = ISNULL;
    tree->entries_num = 0;
  } else {
    // Existing file.

    assert(oldRoot->father == ISNULL &&
	   oldRoot->left   >= 0 &&
	   oldRoot->right  == 0);

    tree->root = oldRoot->data;
    tree->entries_num = oldRoot->left;
  }  
  store_release(tree->nStore, 0);

  return tree;
}

/* validity checks of tree */
/* 
   static BOOL is_father_ptrs_valid(struct btree * tree, struct btree_node * p_node, struct btree_node * father)
   { 
   struct btree *tree;  
   struct btree_node *left, *right;
   BOOL ret = TRUE;
   left = store_read(tree->nStore, p_node->left);
   right = store_read(tree->nStore, p_node->right);
   root =store_read(tree->nStore, p_node->father);
   //  p_node= store_read(tree->nStore, 0);
   assert(p_node->parent == ISNULL);
   assert(p_node->dbObject==ISNULL);
   
   if  (p_node == NULL){
   //    store_release(tree->nStore, 0);
   
   } else if  ( root != father ){
   //    store_release(tree->nStore, 0);     
   ret = FALSE;
   } else if  ( ! is_father_ptrs_valid( tree, left, p_node ) ){
   //    store_release(tree->nStore, 0);
   ret = FALSE;
   } else if  ( ! is_father_ptrs_valid( tree, right, p_node ) ){
   ret = FALSE;  
   //    store_release(tree->nStore, 0);
   
   }
   //  store_release(tree->nStore, 0);  
   store_release(tree->nStore, p_node->left);
   store_release(tree->nStore, p_node->right);
   store_release(tree->nStore, p_node->father);
   return ret;    
   }*/
/*  
    static BOOL is_order_valid(struct btree_node * p_node)
    {
    struct btree *tree;  
    
    p_node=store_read(tree->nStore, 0);
    if  ( p_node == NULL ){
    store_release(tree->nStore, 0);
    return  TRUE;
    }
    
    if  ( p_node->left != NULL ) {
    if  (  p_node->left->data > p_node->data ){
    store_release(tree->nStore, 0);
    return  FALSE;
    }
    }
    if  ( p_node->right != NULL ) {
    if  (  p_node->data > p_node->right->data ){
    store_release(tree->nStore, 0);
    return  FALSE;
    }
    }
    
    if  ( ! is_order_valid( p_node->left ) ){
    store_release(tree->nStore, 0);
    return  FALSE;
    }
    if  ( ! is_order_valid( p_node->right ) ){
    store_release(tree->nStore, 0);
    return  FALSE;
    }
    store_release(tree->nStore, 0);
    return TRUE;           
}*/
/*
  BOOL btree_is_valid( struct btree * p_btree)
  { 
  struct btree *p_tree;   
  struct btree_node *p_node= store_read(p_btree->nStore, 0);   
  assert( p_btree != NULL );
  
  if  ( count_nodes( p_btree->root ) != p_btree->entries_num ) {
  fprintf( stderr, "btree_is_valid:elements number wrong!\n" );
  store_release(p_btree->nStore, 0);
  return  FALSE;
  }
  
  if  ( ! is_father_ptrs_valid( p_btree->root, NULL ) ) {
  fprintf( stderr, "btree_is_valid:father pointers wrong!\n" );
  store_release(p_btree->nStore, 0);
  return  FALSE;
  }
  
  if  ( ! is_order_valid( p_btree->root ) ) {
  fprintf( stderr, "btree_is_valid:order wrong!\n" );
  store_release(p_btree->nStore, 0);
  return  FALSE;
  }
  store_release(p_btree->nStore, 0);
  return TRUE;
  //store_release(p_btree->nStore, 0);
  }*/

/*static int count_nodes(struct btree_node * p_node)
  {
  struct btree *tree;
  p_node= store_read(tree->nStore, 0);
  if   ( p_node == NULL ){
  store_release(tree->nStore, 0);
  return  0;
  }
  else{
  store_release(tree->nStore, 0);
  return  1 + count_nodes( p_node->left ) + count_nodes( p_node->right );
  }
  }*/

/*-- Code for inserting new node -------------------------------*/
static void node_init( struct btree_node * p_node, off_t data )
{
  //    memset( p_node, 0, sizeof( struct btree_node ) );
  p_node->left = ISNULL;
  p_node->right = ISNULL;
  p_node->father = ISNULL;
  
  p_node->data = data;

}

static void bintree_insert(struct btree * p_btree, off_t data)
{
  struct btree_node * pptr;//, * father;

  off_t new_idx;
  struct btree_node * new;
  off_t last_read = p_btree->root;
  off_t next_read;

  void * data_ptr = store_read(p_btree->oStore, data);

  pptr= store_read(p_btree->nStore, p_btree->root);
  
  //  father = ISNULL;
  
  new_idx = store_new(p_btree->nStore);
  new = store_read(p_btree->nStore, new_idx);
  node_init(new, data);
  
  while  ( pptr != NULL ) {
    //    father = last_read;
    void * pptr_data_ptr = store_read(p_btree->oStore, pptr->data);
    int cmp = p_btree->compare(data_ptr, pptr_data_ptr);
    store_release(p_btree->oStore, pptr->data);
    //    if  (  data > pptr->data ) {
    if(cmp == GT) {

      next_read = pptr->right;
      if(next_read == ISNULL) {
	pptr->right = new_idx;
	new->father = last_read;
	store_write(p_btree->nStore, last_read);
      }

    } else {

      next_read = pptr->left;
      if(next_read == ISNULL) {
	pptr->left = new_idx;
	new->father = last_read;
	store_write(p_btree->nStore, last_read);
      }
      
    }
    store_release(p_btree->nStore, last_read);
    if(next_read != ISNULL) {
      pptr = store_read(p_btree->nStore, next_read);
      last_read = next_read;
    } else {
      pptr = NULL;
    }
    
  }
  
  store_release(p_btree->oStore, data);

  store_write(p_btree->nStore, new_idx);
  store_release(p_btree->nStore, new_idx);

}

void btree_insert(struct btree * tree, off_t data)
{
 
  assert( tree != NULL );
  if(tree->root == ISNULL) {
    off_t node_idx;
    struct btree_node * node;

    assert(tree->entries_num == 0);

    node_idx = store_new(tree->nStore);
    node = store_read(tree->nStore, node_idx);
    node_init(node,data);
    store_write(tree->nStore, node_idx);
    store_release(tree->nStore, node_idx);

    tree->root = node_idx;

  } else {

    bintree_insert( tree, data );
    
  }

  tree->entries_num++;

  //  assert( btree_is_valid( p_btree ) );

}

static off_t write_ptr_to_ptr( struct btree * p_btree, struct btree_node * ptr, off_t ptr_idx, off_t new )
{

  off_t ret = ISNULL;
  struct btree_node * ptr_father;

  assert( ptr != NULL );
  
  if ( ptr->father == ISNULL ) {
    ret =  p_btree->root;
    p_btree->root = new;
  } else {  
    ptr_father = store_read(p_btree->nStore, ptr->father);
    if  ( ptr_father->left == ptr_idx ) {
      ret =  ptr_father->left;
      ptr_father->left = new;
    } else if  ( ptr_father->right == ptr_idx ) {
      ret =  ptr_father->right;
      ptr_father->right = new;
    }
    store_write(p_btree->nStore, ptr->father);
    store_release(p_btree->nStore, ptr->father);
  }

  assert(ret != ISNULL);

  return  ret;
}

/* rotate_left:
 *      a     -->       c
 *   b     c         a     e
 *        d e       b d                                 */
static void btree_rotate_left( struct btree  * p_btree, struct btree_node * a, off_t a_idx )
{
  struct btree_node /* ** pp_a, */ * b, * c, * d, * e;
  off_t b_idx, c_idx, d_idx, e_idx;
  off_t father_a;
  
  //   a= store_read(p_btree->nStore, a_idx);    
  assert(a != NULL  &&  a->right != ISNULL);
  
  b_idx = a->left;
  c_idx = a->right;
  
  if(b_idx == ISNULL) {
    b = NULL; 
  } else {
    b = store_read(p_btree->nStore, b_idx);
  }
  if(c_idx == ISNULL) {
    c = NULL; 
  } else {
    c = store_read(p_btree->nStore, c_idx);
  }
  
  
  d_idx = c->left;
  e_idx = c->right;
  
  if(d_idx == ISNULL) {
    d = NULL; 
  } else {
    d = store_read(p_btree->nStore, d_idx);
    }
  if(e_idx == ISNULL) {
    e = NULL; 
  } else {
    e = store_read(p_btree->nStore, e_idx);
  }
  
  //    pp_a = get_ptr_to_ptr(p_btree, a);
  
    /*    b = a->left;
	  c = a->right;
	  d = c->left;
	  e = c->right; */
  
    //    *pp_a = c;
  
  write_ptr_to_ptr(p_btree, a, a_idx, c_idx);
  
  c->left = a_idx;
  c->right = e_idx;
  
  a->left = b_idx;
  a->right = d_idx;
  
  /* fix father pointers */
  father_a = a->father;
  
  a->father = c_idx;
  if ( e != NULL )
    e->father = c_idx;
  
  if ( b != NULL )
    b->father = a_idx;
  if ( d != NULL )
    d->father = a_idx;
  
  c->father = father_a;
  
  if(a_idx != ISNULL){ store_write(p_btree->nStore, a_idx); }
  if(b_idx != ISNULL){ store_write(p_btree->nStore, b_idx); store_release(p_btree->nStore, b_idx); }
  if(c_idx != ISNULL){ store_write(p_btree->nStore, c_idx); store_release(p_btree->nStore, c_idx); }
  if(d_idx != ISNULL){ store_write(p_btree->nStore, d_idx); store_release(p_btree->nStore, d_idx); }
  if(e_idx != ISNULL){ store_write(p_btree->nStore, e_idx); store_release(p_btree->nStore, e_idx); }
  
}

/* rotate_right:
 *      a     -->       c
 *   c     b         e     a
 *  e d                   d b                               */
static void btree_rotate_right( struct btree * p_btree, struct btree_node * a, off_t a_idx )
{
  struct btree_node /* ** pp_a, */ * b, * c, * d, * e;

  off_t father_a;

  off_t b_idx, c_idx, d_idx, e_idx;

  assert( a != NULL  &&  a->left != ISNULL );
  
  b_idx = a->right;
  c_idx = a->left;
  
  if(b_idx == ISNULL) {
    b = NULL; 
  } else {
    b = store_read(p_btree->nStore, b_idx);
  }
  if(c_idx == ISNULL) {
    c = NULL; 
  } else {
    c = store_read(p_btree->nStore, c_idx);
  }
  
  d_idx = c->right;
  e_idx = c->left;
  
  
  if(d_idx == ISNULL) {
    d = NULL; 
  } else {
    d = store_read(p_btree->nStore, d_idx);
  }
  if(e_idx == ISNULL) {
    e = NULL; 
  } else {
    e = store_read(p_btree->nStore, e_idx);
  }
  
  //    pp_a = get_ptr_to_ptr( p_btree, a );
  
  /*    b = a->right;
	c = a->left;
	d = c->right;
	e = c->left;*/
  
  //    *pp_a = c;
  
  write_ptr_to_ptr( p_btree, a, a_idx, c_idx);
  c->right = a_idx;
  c->left = e_idx;
  
  a->right = b_idx;
  a->left = d_idx;
  
  /* fix father pointers */
  father_a = a->father;
  
  a->father = c_idx;
  if ( e != NULL )
    e->father = c_idx;

  if ( b != NULL )
    b->father = a_idx;
  if ( d != NULL )
    d->father = a_idx;
  
  c->father = father_a;
  
  if(a_idx != ISNULL) {store_write(p_btree->nStore, a_idx); }
  if(b_idx != ISNULL) {store_write(p_btree->nStore, b_idx); store_release(p_btree->nStore, b_idx);}
  if(c_idx != ISNULL) {store_write(p_btree->nStore, c_idx); store_release(p_btree->nStore, c_idx);}
  if(d_idx != ISNULL) {store_write(p_btree->nStore, d_idx); store_release(p_btree->nStore, d_idx);}
  if(e_idx != ISNULL) {store_write(p_btree->nStore, e_idx); store_release(p_btree->nStore, e_idx);}

}

static void btree_rotate_up( struct btree * p_btree, struct btree_node * p_node, off_t p_node_idx )
{
    struct btree_node * father_ptr;
    off_t last_read;
    assert( p_node != NULL );

    /* is p_node the root of the tree? */
    if  ( p_node->father == ISNULL ) {
      //        assert( p_btree->root == p_node );

	return;
    }

    father_ptr = store_read(p_btree->nStore, p_node->father);
    last_read = p_node->father;

    if  ( father_ptr->left == p_node_idx ) {
      btree_rotate_right( p_btree, father_ptr, p_node->father);

    } else if  ( father_ptr->right == p_node_idx ) {
      btree_rotate_left( p_btree, father_ptr, p_node->father );
    } else {
      assert(FALSE); /* something is wrong ! */
    } 
    store_release(p_btree->nStore, last_read);
}

static off_t get_valid_son( struct btree_node * p_node )
{
  off_t ret;

  if ( p_node->right == ISNULL )
    ret = p_node->left;
  else 
    ret = p_node->right;

  return ret;
}

/* to delete a p_node, we rotate it down the tree, and remove it when
 * it becomes a leaf */
void btree_delete_node( struct btree * p_btree, struct btree_node * p_node, off_t p_node_idx )
{
  off_t son_idx;

  assert( p_node != NULL );
  while  ( p_node->left != ISNULL  ||  p_node->right != ISNULL ) {
    son_idx = get_valid_son( p_node );
    
    btree_rotate_up( p_btree, store_read(p_btree->nStore, son_idx), son_idx );
    store_release(p_btree->nStore, son_idx);
  }
  
  
  write_ptr_to_ptr(p_btree, p_node, p_node_idx, ISNULL);
  
  //  store_delete(p_btree->nStore, p_node_idx);

  p_btree->entries_num--;
  
  //  assert(btree_is_valid(p_btree));

}

BOOL btree_delete(struct btree * tree, void* data)
{
  // off_t res;
 BOOL ret = FALSE;
 off_t last_read;
 struct btree_node * p_node;

 assert( tree != NULL );
 if(tree->root == ISNULL) {
   return FALSE;
 }

 p_node = store_read(tree->nStore, tree->root);

 last_read = tree->root;
 // res = -1;
 while  ( p_node != NULL ) {
   //   res =  data - p_node->data;
   void * p_node_data_ptr = store_read(tree->oStore, p_node->data);
   int cmp = tree->compare(data, p_node_data_ptr);
   store_release(tree->oStore, p_node->data);
   if  ( cmp == 0 ) {
     btree_delete_node( tree, p_node, last_read );
     store_release(tree->nStore, last_read);
     ret = TRUE;
     p_node = NULL;
   } else {
     off_t next_read;
     if(cmp == GT) {
       //     if(res > 0) {
       if(p_node->right != ISNULL) {
	 next_read = p_node->right;
       } else {
	 next_read = ISNULL;
       }
     } else {
       if(p_node->left != ISNULL) {
	 next_read = p_node->left;
       } else {
	 next_read = ISNULL;
       }
     }
     store_release(tree->nStore, last_read);
     if(next_read != ISNULL) {
       p_node = store_read(tree->nStore, next_read);
       last_read = next_read;
     } else {
       p_node = NULL;
     }
   }

 }

 return ret;
}

/*static void free_tree( struct btree_node * p_node )
{
    struct btree *p_btree;
    p_node= store_read(p_btree->nStore, 0);
    if  ( p_node == NULL )
        return;
    free_tree( p_node->left );
    free_tree( p_node->right );
    store_close (p_btree->nStore);
    store_release(p_btree->nStore, 0);
    free(p_node);
}*/

/*void btree_init(struct btree * p_btree)
{
    assert( p_btree != NULL );

    memset( p_btree, 0, sizeof(struct btree ) );
}
*/
void btree_close( struct btree * p_btree )
{
  struct btree_node * root = store_read(p_btree->nStore, 0);

  root->data = p_btree->root;
  root->left = p_btree->entries_num;

  store_write  (p_btree->nStore, 0);
  store_release(p_btree->nStore, 0);

  assert( p_btree != NULL );
  
  //printf( "Btree entires number: %d\n", p_btree->entries_num );
  
  store_close(p_btree->nStore);

  free(p_btree);

}

/*static int tree_depth( struct btree_node * node )
  {
  int left, right;
  struct btree *p_btree;
  node= store_read(p_btree->nStore, 0);
  
  if  ( node == NULL ){
  store_release(p_btree->nStore, 0);
  return  0;
  }
  else {
  left = btree_depth( node->left );
  right = btree_depth( node->right );
  store_release(p_btree->nStore, 0);
  return  1 + ((left > right)? left : right );
  }
  }
  
  off_t btree_depth( struct btree * p_btree )
  {
  assert( p_btree != NULL );
  
  return tree_depth( p_btree->root );
  }*/
/*
  struct btree_node * left=NULL, * right=NULL;
  if(node->left != ISNULL) {
  left = store_read(tree->nStore, node->left);
  
  } 
  
  if(node_right != ISNULL) {
  right = store_read(tree->nStore, node->right);
  
  }
  
  if(node->left != ISNULL) {
  store_release(tree->nStore, node->left);
  } else {
  assert(left == NULL);
  }
  if(node->right != ISNULL) {
  store_release(tree->nStore, node->right);
  } else {
  assert(right == NULL);
  }
  
  
  
*/

int btree_find (const struct btree * tree, void* find_data) { 
  int ret;
  const struct btree_node * root = store_read(tree->nStore, tree->root);
  ret = bintree_find(tree, root, tree->root, find_data);
  store_release(tree->nStore, tree->root);
  return ret;
}

int bintree_find (const struct btree * tree, const struct btree_node * node, off_t node_idx, void * find_data)
{
  //  const struct btree_node * left = NULL, * right = NULL;

  int ret = -1;
  int cmp ;
  void * node_data_ptr;

  if (node == NULL){
    printf ("Item not found in tree\n");
  }
  /*  if(node->left != ISNULL) {
    left = store_read(tree->nStore, node->left);

    } 
    
    if(node->right != ISNULL) {
    right = store_read(tree->nStore, node->right);
    
    }*/

  node_data_ptr = store_read(tree->oStore, node->data);
  cmp = tree->compare(find_data, node_data_ptr);
  store_release(tree->oStore, node->data);

  if(cmp == EQ) {
  //  if (find_data == node->data){
    printf ("Item found. (%ld)\n" , (long int) *(off_t*)find_data);
    ret = 1;
  } else if (cmp == LT) {
    //  } else if (find_data < node->data){
    if(node->left == ISNULL) {
      ret = 0;
    } else {
      struct btree_node * left = store_read(tree->nStore, node->left);

      assert(left->father == node_idx);
      ret = bintree_find (tree, left, node->left, find_data /*, depth+1*/);
      store_release(tree->nStore, node->left);
    }
  } else {
    if(node->right == ISNULL) {
      ret = 0; 
    } else {
      struct btree_node * right = store_read(tree->nStore, node->right);

      assert(right->father == node_idx);
      ret = bintree_find (tree, right, node->right, find_data /*, depth+1*/);
      store_release(tree->nStore, node->right);
    }
  }

  /*
    if(node->left != ISNULL) {
    store_release(tree->nStore, node->left);
    } else {
    assert(left == NULL);
    }
    if(node->right != ISNULL) {
    store_release(tree->nStore, node->right);
    } else {
    assert(right == NULL);
    }
  */
  return ret; 
} 

void btree_query (const struct btree * tree, void* find_data, void*(*handler)(const void*,void*), void * handler_state) { 
  const struct btree_node * root = store_read(tree->nStore, tree->root);
  bintree_query(tree, root, find_data, handler, handler_state);
  store_release(tree->nStore, tree->root);

}

void bintree_query (const struct btree * tree, const struct btree_node * node, void * find_data,
		    void*(*handler)(const void*,void*), void * handler_state){
  //  const struct btree_node * left = NULL, * right = NULL;

  int cmp ;
  void * node_data_ptr;

  if (node == NULL){
    printf ("Item not found in tree\n");
  }
  /*  if(node->left != ISNULL) {
    left = store_read(tree->nStore, node->left);

    } 
    
    if(node->right != ISNULL) {
    right = store_read(tree->nStore, node->right);
    
    }*/

  node_data_ptr = store_read(tree->oStore, node->data);
  cmp = tree->compare(find_data, node_data_ptr);
  store_release(tree->oStore, node->data);

  if (cmp == LT || cmp == EQ) {
    //  } else if (find_data < node->data){
    if(cmp == EQ) {
      //Item found.
      handler(find_data, handler_state);
    }
    if(node->left == ISNULL) {

    } else {
      struct btree_node * left = store_read(tree->nStore, node->left);
      bintree_query (tree, left, find_data, handler, handler_state);
      store_release(tree->nStore, node->left);
    }
  } else {
    if(node->right == ISNULL) {

    } else {
      struct btree_node * right = store_read(tree->nStore, node->right);
      bintree_query (tree, right, find_data, handler, handler_state);
      store_release(tree->nStore, node->right);
    }
  }

  /*
    if(node->left != ISNULL) {
    store_release(tree->nStore, node->left);
    } else {
    assert(left == NULL);
    }
    if(node->right != ISNULL) {
    store_release(tree->nStore, node->right);
    } else {
    assert(right == NULL);
    }
  */

} 

static void print_subtree(const struct btree * tree, int depth, struct btree_node * node, off_t node_idx ){
  off_t i ;

  
  //  void * node_data_ptr = store_read(tree->oStore, node->data);

  //  struct btree_node * left, * right;

  //struct btree * p_btree;
  // node = store_read(p_btree->nStore, 0);
    if  ( node == NULL )
        return;



    if(node->left != ISNULL) {
      struct btree_node * left = store_read(tree->nStore, node->left);

      assert(left->father == node_idx);

      print_subtree(tree, depth + 1, left, node->left);
      store_release(tree->nStore, node->left);
    } else {
      for(i = 0; i < depth; i++) {
	printf("\t");
      }
      
      printf("-\n");
    }
    for(i = 0; i < depth; i++) {
      printf("\t");
    }
    printf( "%ld\n", (long int)node->data ); 

    if(node->right != ISNULL) {
      struct btree_node * right = store_read(tree->nStore, node->right);
      
      assert(right->father == node_idx);
      
      print_subtree(tree, depth + 1, right, node->right);
      store_release(tree->nStore, node->right);
    //store_release(p_btree->nStore, 0);

    } else {
    for(i = 0; i < depth; i++) {
      printf("\t");
    }
           printf("-\n");
    }

    //    store_release(tree->oStore, node->data);
    
    //    printf( ") "); 
}

void btree_print(const struct btree * p_btree )
{
    printf( "binary tree:\n" );
    if  ( p_btree->root == ISNULL ) {
        printf( "@    <<EMPTY BTREE>>\n" );
        return;
    }
    print_subtree(p_btree, 0, store_read(p_btree->nStore, p_btree->root), p_btree->root );
    store_release(p_btree->nStore, p_btree->root);
    printf( "\n" );

    fflush( stdout );
    fflush( stderr );
}
